package br.ufrgs.meetapp.activities;

import java.util.ArrayList;

import android.content.Context;
import android.content.Intent;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.Toast;
import br.ufrgs.meetapp.control.BalloonItemizedOverlay;
import br.ufrgs.meetapp.control.FixedMyLocationOverlay;
import br.ufrgs.meetapp.models.Buddy;
import br.ufrgs.meetapp.models.User;
import br.ufrgs.meetapp.utils.UserPreferencesPersistence;
import br.ufrgs.meetapp.webservices.MFTWebServiceClient;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.maps.OverlayItem;


public class TrackOthersMapActivity extends MapActivity implements OnClickListener{

	private MapView mapView = null;
	private MapController mapController = null;
	private FixedMyLocationOverlay myLocationOverlay;
	private Context context;
	private Button leftButton;
	private ImageButton refreshButton;
	private Button rightButton;
	private ImageButton centerInMyLocationButton;
	private ImageView logoImageView;
	private MFTItemizedOverlay itemizedBuddyOverlay;
	public static MFTItemizedOverlay itemizedMeetingOverlay;
	private OverlayMap tapOverlay;
	private int deviceSelectedIndex = 0;
	private boolean zoomToSpan;
	private ArrayList<Buddy> buddyList;
	private ArrayList<Buddy> filteredBuddyList;
	private ProgressBar refreshActivityIndicator;
	private boolean isBuddySelected = false;
	
	
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		setContentView(R.layout.track_others_map_activity);
		
		context = this;

		buddyList = new ArrayList<Buddy>();
		filteredBuddyList = new ArrayList<Buddy>();
		
		zoomToSpan = true;
		
		initializeViews();
		setLocation();

		new RefreshBuddyListTask().execute();
	}
	
	/**
	 * Initialize views, images, buttons, map view
	 */
	private void initializeViews() {
		leftButton = (Button)findViewById(R.id.track_others_activity_left_button);
		leftButton.setOnClickListener(this);
		
		refreshButton = (ImageButton)findViewById(R.id.track_others_activity_refresh_button);
		refreshButton.setOnClickListener(this);
		
		rightButton = (Button)findViewById(R.id.track_others_activity_right_button);
		rightButton.setOnClickListener(this);
		
		
		centerInMyLocationButton = (ImageButton)findViewById(R.id.track_others_activity_my_location_button);
		centerInMyLocationButton.setOnClickListener(this);
		
		//instantiate the MapView
        mapView = (MapView) findViewById(R.id.track_others_activity_map_view);
        mapView.setSatellite(true);
        //instantiate the mapController
        mapController = mapView.getController();
        
        Drawable drawable = mapView.getContext().getResources().getDrawable(R.drawable.map_marker);
        itemizedBuddyOverlay = new MFTItemizedOverlay(drawable, mapView);
        
        Drawable drawable2 = mapView.getContext().getResources().getDrawable(R.drawable.marker_large);
        itemizedMeetingOverlay = new MFTItemizedOverlay(drawable2, mapView);
        
        tapOverlay = new OverlayMap(drawable,mapView);
        
        refreshActivityIndicator = (ProgressBar) findViewById(R.id.track_others_map_activity_activity_indicator);
	}
	
	/**
	 * Initialize the LocationManager that handles the user location.
	 */
	private void setLocation(){ 
		
		myLocationOverlay = new FixedMyLocationOverlay(this, mapView);
		mapView.getOverlays().add(myLocationOverlay);
		mapView.getOverlays().add(itemizedBuddyOverlay);
		mapView.getOverlays().add(itemizedMeetingOverlay);

		//Set Center when receives the first signal and draw the icon
		myLocationOverlay.runOnFirstFix(new Runnable() {
			public void run() {
				mapController.animateTo(myLocationOverlay.getMyLocation());
			}
		});
	}

	@Override
	protected void onResume() {
		super.onResume();
		
		myLocationOverlay.enableMyLocation();
		myLocationOverlay.enableCompass();

		try {
			if(TrackOthersTabActivity.buddyList != null){
				buddyList = TrackOthersTabActivity.buddyList;
			}
			refreshDevices();
			
			//Check if there is a buddy selected
			if(TrackOthersTabActivity.isBuddySelected){
				TrackOthersTabActivity.isBuddySelected = false;
				Buddy buddySelected = TrackOthersTabActivity.buddySelected;
				int index = 0;
				
				//check if there is a filter 
				if(TrackOthersTabActivity.filteredIds.isEmpty()){
					//if no, select from the buddy list without filter
					for(Buddy buddy : buddyList){
						if(buddy.getBuddyId() == buddySelected.getBuddyId()){
							itemizedBuddyOverlay.onTap(index);
							break;
						}
						index++;
					}
					
				} else {
					//if yes, select from the list with filter
					for(Buddy buddy : filteredBuddyList){
						if(buddy.getBuddyId() == buddySelected.getBuddyId()){
							itemizedBuddyOverlay.onTap(index);
							break;
						}
						index++;
					}
				}	
				
				mapController.setZoom(16);
			}
		} catch (Exception exception) {

			System.out
					.println("Error in TrackOthersMapActivity.onResume - trying to Select an item ");
			if (exception.getMessage() != null)
				System.out.println(exception.getMessage());
			exception.printStackTrace();
			
			new RefreshBuddyListTask().execute();
		}
	}

	@Override
	protected void onPause() {
		if(buddyList!= null && !buddyList.isEmpty()){
			TrackOthersTabActivity.buddyList = buddyList;
		}
		
		//Check if there is a balloon focused, if yes, update the buddy selected
		if (itemizedBuddyOverlay.getFocus() != null){
			isBuddySelected = true;
			if (filteredBuddyList.isEmpty()) {
				TrackOthersTabActivity.buddySelected = buddyList.get(itemizedBuddyOverlay.getLastFocusedIndex());
			} else {
				TrackOthersTabActivity.buddySelected = filteredBuddyList.get(itemizedBuddyOverlay.getLastFocusedIndex());
			}
			
		}
		
		TrackOthersTabActivity.myLocation = myLocationOverlay.getMyLocation();
		myLocationOverlay.disableMyLocation();
		myLocationOverlay.disableCompass();		
		
		super.onPause();
	}
	
	/**
	 * Refresh the overlay with the tracked devices on the map
	 */
	private void refreshDevices() {
		try {
			if (!buddyList.isEmpty()){
				itemizedBuddyOverlay.clear();
				filteredBuddyList.clear();
				
				if(TrackOthersTabActivity.filteredIds.isEmpty()){
					
					for (Buddy currentBuddy : buddyList){
						addBuddyToOverlay(currentBuddy);
					}
				} else {
					for (Buddy currentBuddy : buddyList){
						if(TrackOthersTabActivity.filteredIds.contains(currentBuddy.getBuddyId())){
							addBuddyToOverlay(currentBuddy);
							filteredBuddyList.add(currentBuddy);
						}
					}
					if(isBuddySelected){						
						isBuddySelected = false;
						
						if(TrackOthersTabActivity.filteredIds.contains(TrackOthersTabActivity.buddySelected.getBuddyId())){
							itemizedBuddyOverlay.onTap(TrackOthersTabActivity.filteredIds.indexOf(TrackOthersTabActivity.buddySelected.getBuddyId()));
						}else{
							itemizedBuddyOverlay.hideAllBalloons();
							zoomToBuddySpam(filteredBuddyList);
						}
					}
				}		
				
				if(zoomToSpan){
					zoomToSpan = false;
					zoomToBuddySpam(buddyList);
				}
			}
			//Refresh Map
			mapView.invalidate();
			
		} catch (Exception exception) {

			System.out
					.println("Error in TrackOthersMapActivity.refreshDevices - trying to refresh itemizedoverlay");
			if (exception.getMessage() != null)
				System.out.println(exception.getMessage());
			exception.printStackTrace();
		}
		
		
	}
	
	/**
	 * Receives a buddy and add it on the overlay
	 * @param buddy
	 */
	private void addBuddyToOverlay(Buddy buddy){
		GeoPoint buddyGeoPoint; 
		try{
			buddyGeoPoint = new GeoPoint(buddy.getLatitude(), buddy.getLongitude());
			String description = "";
			try{
				description = buddy.getPositionDate().toLocaleString(); 
			}
			catch (Exception ex)
			{
				Log.i("MFT - TrackOthersMapActivity ", "Error converting date: "+ex.getMessage());
			}
			description+= "\n" + TrackOthersTabActivity.getDistanceBetweenTwoGeoPoints(myLocationOverlay.getMyLocation(), buddyGeoPoint);
			itemizedBuddyOverlay.addOverlay(new OverlayItem(buddyGeoPoint, buddy.getBuddyName(), description));
		}
		catch (Exception ex)
		{
			Log.i("MFT - TrackOthersMapActivity ", "Error creating map pin: "+ex.getMessage());
		}
	}
	
	
	/**
	 * Navigate do the next device on the overlay list
	 */
	private void navigateToNextDevice() {
		deviceSelectedIndex ++;
		if(deviceSelectedIndex >= itemizedBuddyOverlay.size()){
			deviceSelectedIndex = 0;
		}
		
		if (itemizedBuddyOverlay.size() != 0 && itemizedBuddyOverlay != null){
			mapController.animateTo(itemizedBuddyOverlay.getItem(deviceSelectedIndex).getPoint());
			itemizedBuddyOverlay.onTap(deviceSelectedIndex);
		}
	}
	
	
	/**
	 * Navigate do the previous device on the overlay list
	 */
	private void navigateToPreviousDevice() {
		deviceSelectedIndex --;
		if(deviceSelectedIndex < 0){
			deviceSelectedIndex = itemizedBuddyOverlay.size() - 1;
		}
		
		if (itemizedBuddyOverlay.size() != 0 && itemizedBuddyOverlay != null){
			mapController.animateTo(itemizedBuddyOverlay.getItem(deviceSelectedIndex).getPoint());
			itemizedBuddyOverlay.onTap(deviceSelectedIndex);
		}
		
	}
	
	/**
	 * Asynchronous task to call the Web service to update the buddies informations
	 */
	private class RefreshBuddyListTask extends AsyncTask<Void, Void, Void>{
		private boolean isValidBuddies = false;

		@Override
		protected void onPreExecute() {
			refreshButton.setVisibility(View.INVISIBLE);
			refreshActivityIndicator.setVisibility(View.VISIBLE);
			super.onPreExecute();
		}
		
		@Override
		protected Void doInBackground(Void... params) {
			MFTWebServiceClient webService = new MFTWebServiceClient();
						
			try {
				Log.i("TrackOthersMapActivity", "Calling WS to Refresh BuddyList");
				
				User user = new User();
				
				user = LoginActivity.loggedUser;
				
				//buddyList = webService.listBuddies(user);
							
			} catch (Exception e) {
				System.out.println("Error in TrackOthersMapActivity.RefreshBuddyListTask.doInBackground - trying to call WS to Refresh BuddyList");

				if (e.getMessage() != null) {
					System.out.println(e.getMessage());
				}

				e.printStackTrace();
			}
			
			if (buddyList != null && !buddyList.isEmpty()) {
				isValidBuddies = true;
			}
			return null;
		}
		

		@Override
		protected void onPostExecute(Void result) {
			if (isValidBuddies) {
				refreshDevices();	
			}
			refreshButton.setVisibility(View.VISIBLE);
			refreshActivityIndicator.setVisibility(View.INVISIBLE);
			
			//If one buddy was focused, refresh the balloon
			try {
				if (itemizedBuddyOverlay.getFocus() != null){
					itemizedBuddyOverlay.onTap(itemizedBuddyOverlay.getLastFocusedIndex());
				}
			} catch (Exception exception) {

				System.out
						.println("Error in TrackOthersMapActivity.onPostExecute - trying to refresh the balloon tap");
				if (exception.getMessage() != null)
					System.out.println(exception.getMessage());
				exception.printStackTrace();
			}
			
			
			super.onPostExecute(result);
		}	
	}
	
	/**
	 * Switch to List Tab
	 */
	public void switchToListTab(){
        TrackOthersTabActivity ParentActivity;
        ParentActivity = (TrackOthersTabActivity) this.getParent();
        ParentActivity.switchTab(TrackOthersTabActivity.TAB_LIST);
	}
	

	@Override
	protected boolean isRouteDisplayed() {
		return false;
	}	
	
	/**
	 * Center the map in My Location
	 */
	private void centerInMyLocation() {
		if(myLocationOverlay.getMyLocation() != null){
			mapController.animateTo(myLocationOverlay.getMyLocation());
			mapController.setZoom(16);
		}
		
	}	
	
	private class OverlayMap extends Overlay {

		/**
		 * Create a map overlay with a Default Marker
		 * 
		 * @param defaultMarker
		 * @param mapView
		 */
		public OverlayMap(Drawable defaultMarker, MapView mapView) {
			
		}
		
		 @Override
		 public boolean onTap(GeoPoint point, MapView mapView) 
		 {
		   Context contexto = mapView.getContext();
		   String msg = "Lat: " + point.getLatitudeE6()/1E6 + " - " + 
		                "Lon: " + point.getLongitudeE6()/1E6;

		   Toast toast = Toast.makeText(contexto, msg, Toast.LENGTH_SHORT);
		   toast.show();

		  return true;
		 }
		}
	
	/**
	 * Custom ItemizedOverlay for the MFT project;
	 */
	public class MFTItemizedOverlay extends BalloonItemizedOverlay<OverlayItem>{
		private ArrayList<OverlayItem> mOverlays = new ArrayList<OverlayItem>();
		
		/**
		 * Create a map overlay with a Default Marker
		 * 
		 * @param defaultMarker
		 * @param mapView
		 */
		public MFTItemizedOverlay(Drawable defaultMarker, MapView mapView) {
			super(boundCenter(defaultMarker), mapView);
			populate();
		}
		
		/**
		 * Add an overlay to overlay List
		 * @param overlay
		 */
		public void addOverlay(OverlayItem overlay) {
		    mOverlays.add(overlay);
		    populate();
		}

		@Override
		protected OverlayItem createItem(int i) {
			return mOverlays.get(i);
		}

		@Override
		public int size() {
			return mOverlays.size();
		}
		
		/**
		 * Removes all items from the overlay
		 */
		public void clear() {
	        mOverlays.clear();
	        populate();
	    }
		
		@Override
		protected boolean onBalloonTap(int index, OverlayItem item) {
			TrackOthersTabActivity.isBuddySelected = true;
			if(filteredBuddyList.isEmpty()){
				TrackOthersTabActivity.buddySelected = buddyList.get(index);
			} else {
				TrackOthersTabActivity.buddySelected = filteredBuddyList.get(index);
			}
			
			switchToListTab();
			return true;
		}
		
	}
	
	/**
	 * Set the zoom and center of the map to show all buddies
	 */
	private void zoomToBuddySpam(ArrayList<Buddy> buddies){	
		int minLat = Integer.MAX_VALUE;
		int maxLat = Integer.MIN_VALUE;
		int minLon = Integer.MAX_VALUE;
		int maxLon = Integer.MIN_VALUE;

		for (Buddy currentBuddy : buddies){
		      int lat = currentBuddy.getLatitude();
		      int lon = currentBuddy.getLongitude();

		      maxLat = Math.max(lat, maxLat);
		      minLat = Math.min(lat, minLat);
		      maxLon = Math.max(lon, maxLon);
		      minLon = Math.min(lon, minLon);
		 }

		mapController.zoomToSpan(Math.abs(maxLat - minLat), Math.abs(maxLon - minLon));
		mapController.animateTo(new GeoPoint( (maxLat + minLat)/2, 
		(maxLon + minLon)/2 )); 
	}
	
	/**
	 * Create the hard-button menu
	 */
	public boolean onCreateOptionsMenu(Menu menu){
    	super.onCreateOptionsMenu(menu);
    	MenuInflater menuInflater = getMenuInflater();
    	if(UserPreferencesPersistence.getIsOnlyTrackOthers(context)){
    		menuInflater.inflate(R.menu.menu_account_about, menu);
    	} else {
    		menuInflater.inflate(R.menu.menu_settings_account_about, menu);
    	}
    	return true;
    }
    
	/**
	 * Actions to the hard-button menu
	 */
	public boolean onOptionsItemSelected(MenuItem item) {
		Intent intent = null;
		switch (item.getItemId()) {
		case R.id.menuSettings:
			intent = new Intent(context, SettingsActivity.class);
			break;
//		case R.id.menuAccount:
//			intent = new Intent(context, AccountActivity.class);
//			break;
		case R.id.menuAbout:
			intent = new Intent(context, AboutActivity.class);
			break;
		}

		if(intent!=null){
			intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
			startActivity(intent);
			return true;
		}
		
		return false;
	}

	@Override
	public void onClick(View view) {
		switch (view.getId()) {
		case R.id.track_others_activity_my_location_button:
			centerInMyLocation();
			break;
		case R.id.track_others_activity_left_button:
			navigateToPreviousDevice();
			break;
		case R.id.track_others_activity_refresh_button:
			new RefreshBuddyListTask().execute();
			break;
		case R.id.track_others_activity_right_button:
			navigateToNextDevice();
			break;
		default:
			break;
		}
		
	}
	
	
}
